#include "stdafx.h"
#include "Hand.h"
#include "HandInfo.h"
#include "AmtWonLostHandInfoBuilder.h"
#include <cstring>

void AmtWonLostHandInfoBuilder::Fill(HandInfo &handInfo, const Hand &hand)
{
	float amtToCall = hand.Bb();
	int numStreetsPlayed = (int)PREFLOP;
	list<Action> & actionList = hand.Actions();
	list<Action>::iterator actionIt;
	list<Result>::iterator resultIt;
	list<Result> resultList = hand.Results();

	map<string,StateContainer> stateMap;
	map<Street,float>::iterator streetIt;
	bool raiseRoldFlag = false;
	InitializeMap(stateMap, hand);

	// Find the amount lost by each player on each street
	for(actionIt = actionList.begin(); actionIt != actionList.end(); actionIt++)
	{
		if (numStreetsPlayed != (int)actionIt->StreetPos())
		{
			numStreetsPlayed = (int)actionIt->StreetPos();
			amtToCall = 0;
			RefreshMap(stateMap);
		}

		float dummy = ModifyAction(stateMap, (*actionIt), amtToCall, hand, raiseRoldFlag);
		if (dummy != 0) amtToCall = dummy;
	}
	
	// If there are any dirty players at the end of the hand, do something
	if (raiseRoldFlag)
	{
		// If we get here, then the hand ends when a player raises, and everyone else folds
		
		// Modify this
		list<Action>::reverse_iterator ractIt;
		for(ractIt = actionList.rbegin(); ractIt != actionList.rend(); ++ractIt)
		{
			if(ractIt->ActionType() == RAISE)
			{
				stateMap[ractIt->PlayerName()].gainLossMap[ractIt->StreetPos()] += ractIt->Amount();
				break;
			}
		}
	}

	// Add the pot won by each player
	for(resultIt = resultList.begin(); resultIt != resultList.end(); resultIt++)
	{
		string playerName = resultIt->Player();
		float amtLost = 0;
		for(streetIt = stateMap[playerName].gainLossMap.begin(); 
			streetIt != stateMap[playerName].gainLossMap.end();
			streetIt++)
		{
			if ((int)streetIt->first > numStreetsPlayed) break;
			amtLost += streetIt->second;
		}

		handInfo.PlayerInfo(playerName).AmountWonLost(amtLost + resultIt->Amount());
	}
}

void AmtWonLostHandInfoBuilder::InitializeMap(map<string,StateContainer> &stateMap, const Hand &hand)
{
	list<Player>::iterator playerIt;
	list<Player> playerList = hand.Players();

	for(playerIt = playerList.begin(); playerIt != playerList.end(); playerIt++)
	{
		StateContainer state;
		stateMap[(*playerIt).Name()] = state;
	}
}

float AmtWonLostHandInfoBuilder::ModifyAction(map<string,StateContainer> &stateMap, 
											  Action &action, float amtToCall, 
											  const Hand &hand, bool &raiseRoldFlag)
{
	float newAmtToCall = 0;
	Player player;

	switch(action.ActionType())
	{
	case POST:
		// lose blinds
		stateMap[action.PlayerName()].gainLossMap[action.StreetPos()] -= action.Amount();
		raiseRoldFlag = false;
		break;
	case CHECK:
		stateMap[action.PlayerName()].State(CLEAN);
		raiseRoldFlag = false;
		break;
	case CALL:
		stateMap[action.PlayerName()].State(CLEAN);
		player = hand.GetPlayer(action.PlayerName());
		raiseRoldFlag = false;

		// If the player's stack is less than the amt to call
		if (player.Stack() < amtToCall)
			stateMap[action.PlayerName()].gainLossMap[action.StreetPos()] -= action.Amount();
		else stateMap[action.PlayerName()].gainLossMap[action.StreetPos()] = 0 - amtToCall;
		break;
	case BET:
		RefreshMap(stateMap);
		stateMap[action.PlayerName()].State(CLEAN);
		raiseRoldFlag = false;

		newAmtToCall = action.Amount();
		stateMap[action.PlayerName()].gainLossMap[action.StreetPos()] -= newAmtToCall;
		break;
	case RAISE:
		RefreshMap(stateMap);
		stateMap[action.PlayerName()].State(CLEAN);
		raiseRoldFlag = true;

		newAmtToCall = action.Amount() + amtToCall;
		stateMap[action.PlayerName()].gainLossMap[action.StreetPos()] = 0 - newAmtToCall;
		break;
	case FOLD:
		stateMap[action.PlayerName()].State(OUT);
		break;
	default:
		break;
	}

	return newAmtToCall;
}

void AmtWonLostHandInfoBuilder::RefreshMap(map<string,StateContainer> &stateMap)
{
	map<string,StateContainer>::iterator mapIt;
	for (mapIt = stateMap.begin(); mapIt != stateMap.end(); mapIt++)
	{
		if ((mapIt->second).State() == CLEAN)
		{
			mapIt->second.State(DIRTY);
		}
	}
}

StateContainer::StateContainer()
{
	int numStreetEnums = 4;
	state_ = DIRTY;

	for(int i = 0; i < numStreetEnums; i++)
	{
		gainLossMap[(Street)i] = 0;
	}
}